package hn.cch.web.sse.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * SSE只支持从服务器给客户端传输单行数据
 * SSE只支持GET，且无法识别空格和换行
 */
@RequestMapping(value = "/sse")
@Controller
public class SseController {

    private static final Logger logger = LoggerFactory.getLogger(SseController.class);

    public static final Map<String, SseEmitter> sseEmitterMap = new ConcurrentHashMap<>();

    @RequestMapping(value = "/connect/{uid}", method = RequestMethod.GET)
    public SseEmitter connect(@PathVariable(value = "uid") String uid) {
        SseEmitter sseEmitter = null;
        if (sseEmitterMap.containsKey(uid)) {
            sseEmitter = sseEmitterMap.get(uid);
            sseEmitter.complete();
            sseEmitterMap.remove(uid);
        }
        try {
            sseEmitter = new SseEmitter(30 * 1000L);
            sseEmitter.onError(throwable -> {
                logger.error("onError:{}", throwable.getMessage());
                sseEmitterMap.remove(uid);
            });
            sseEmitter.onCompletion(() -> {
                logger.info("onCompletion");
                sseEmitterMap.remove(uid);
            });
            sseEmitter.onTimeout(() -> {
                logger.info("onTimeout");
                sseEmitterMap.remove(uid);
            });
            sseEmitterMap.put(uid, sseEmitter);
            // sseEmitter.send(SseEmitter.event().comment("comment"));
            sseEmitter.send(String.format("%s connect success", uid), MediaType.TEXT_PLAIN);
        } catch (IOException e) {
            logger.error("connect error:{}", e.getMessage());
        }
        return sseEmitter;
    }


    @RequestMapping(value = "/send/{uid}", method = RequestMethod.GET)
    public ResponseEntity<String> send(@PathVariable(value = "uid") String uid, @RequestParam(value = "msg") String
        msg) {
        try {
            if (sseEmitterMap.containsKey(uid)) {
                SseEmitter sseEmitter = sseEmitterMap.get(uid);
                if (StringUtils.isEmpty(msg)) { // 发送内容为空就完成
                    sseEmitter.send("completion and close", MediaType.TEXT_PLAIN);
                    sseEmitter.complete();
                    sseEmitterMap.remove(uid);
                    return ResponseEntity.ok(String.format("msg[%s] is empty %s completion", msg, uid));
                }
                sseEmitter.send(msg, MediaType.TEXT_PLAIN);
                return ResponseEntity.ok(String.format("send %s message %s success", msg, uid));
            } else {
                return ResponseEntity.ok(String.format("%s not exists, %s not send", uid, msg));
            }
        } catch (IOException e) {
            String content = String.format("send[uid:%s,msg:%s] error:%s", uid, msg, e.getMessage());
            logger.error(content);
            sseEmitterMap.remove(uid);
            return ResponseEntity.ok(content);

        }

    }

    @RequestMapping(value = "/sendAll", method = RequestMethod.GET)
    public ResponseEntity<String> sendAll(@RequestParam(value = "msg") String msg) {

        if (StringUtils.isEmpty(msg)) { // 发送内容为空就完成
            return ResponseEntity.ok(String.format("message %s can not empty", msg));
        }
        for (String uid : sseEmitterMap.keySet()) {
            SseEmitter sseEmitter = sseEmitterMap.get(uid);
            try {
                sseEmitter.send(msg, MediaType.TEXT_PLAIN);
            } catch (IOException e) {
                String content = String.format("send[uid:%s,msg:%s] error:%s", uid, msg, e.getMessage());
                logger.error(content);
                sseEmitter.complete();
                sseEmitterMap.remove(uid);
                // return ResponseEntity.ok(content);
            }
        }

        return ResponseEntity.ok(String.format("send %s message all success", msg));
    }

}
